package bamboo.drawingkid.views;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;

import bamboo.drawingkid.controls.ToolbarViewController;
import bamboo.drawingkid.helpers.Rectangle;
import bamboo.drawingkid.views.components.DrawableLine;

public abstract class DrawingView extends GameCanvas {

	public static final int SMALL_BRUSH = 4;
	public static final int MEDIUM_BRUSH = 6;
	public static final int LARGE_BRUSH = 8;
	public static final int XL_BRUSH = 10;

	private Graphics g;
	private Timer mTimer;
	private double brush_x = -1;
	private double brush_y = -1;
	private double previous_x = -1;
	private double previous_y = -1;
	private int brushWidth = SMALL_BRUSH;
	private Image drawing;
	private Image background;
	private Graphics img_g;
	private ToolBarView toolbar;
	private int brushColor = 0x000000;
	private boolean renderDrawing = false;
	private boolean drawingAllowed = true;
	protected boolean isDrawingAllowed() {
		return drawingAllowed;
	}
	protected void setDrawingAllowed(boolean drawingAllowed) {
		this.drawingAllowed = drawingAllowed;
	}
	private Vector buffer;
	private Rectangle drawArea;
	
	protected DrawingView() {
		super(false);
		setFullScreenMode(true);
		int width = getWidth();
		int height = getHeight();
		drawArea = new Rectangle(20, ToolBarView.HEIGHT, width - 20*2, height - ToolBarView.HEIGHT * 2);
		try {
			background = Image.createImage("/Background.png");
		} catch (IOException e) {
			e.printStackTrace();
		}
		drawing = Image.createImage(width, height - ToolBarView.HEIGHT * 2);
		img_g = drawing.getGraphics();

		toolbar = new ToolbarViewController(width, height);
		buffer = new Vector();
	}

	protected void showNotify() {
		mTimer = new Timer();
		g = getGraphics();
		clearGraphic(g);
		g.drawImage(drawing, 0, ToolBarView.HEIGHT, Graphics.LEFT | Graphics.TOP);
		TimerTask ui = new TimerTask() {
			public void run() {
				render(g);
				flushGraphics();
			}
		};
		mTimer.schedule(ui, 0, 20);
	}

	protected void hideNotify() {
		mTimer.cancel();
	}

	protected void render(Graphics g) {
		g.setClip(0, 0, getWidth(), getHeight());
		g.drawImage(background, 0, 0, Graphics.TOP|Graphics.LEFT);
		toolbar.render(g);
		if (renderDrawing) {
			g.drawImage(drawing, drawArea.getX(), drawArea.getY(), Graphics.LEFT
					| Graphics.TOP);
			renderDrawing = false;
		} else {
			if (drawingAllowed) {
				if (!buffer.isEmpty()) {
					renderDrawing();
				}
			} else {
				g.drawImage(drawing, drawArea.getX(), drawArea.getY(), Graphics.LEFT
						| Graphics.TOP);
			}
		}
	}

	private void renderDrawing() {
		g.setColor(brushColor);
		img_g.setColor(brushColor);
		int l = buffer.size();
		DrawableLine[] currentLines = new DrawableLine[buffer.size()];
		for (int i = 0; i < l; i++) {
			currentLines[i] = (DrawableLine) buffer.elementAt(i);
		}
		int s = currentLines.length;
		for (int j = 0; j < s; j++) {
			DrawableLine line = currentLines[j];
			buffer.removeElement(line);
			if (line.endX > 0 && line.endY > 0) {
				if (line.startX > 0 && line.startY > 0) {
					int d = calcDistance();
					if (d > (brushWidth / 2)) {
						// we calculate the unit vector from our line direction
						// vector which is <1, m> m being the slope
						double m = ((line.endY - line.startY) / (line.endX - line.startX));// calculate
																							// slope
						double magnitude = Math.sqrt(1 + m * m);// ie. the
																// length of the
																// direction
																// vector
						double n_x = 1 / magnitude;// x of the unit vector
						double n_y = m / magnitude;// y of the unit vector
						if (line.startX > line.endX) {// we check the direction
														// of the vector and
														// change it if
														// necessary
							n_x = -n_x;
							n_y = -n_y;
						}
						// we draw the dots between the start and the end of the
						// line so that it looks like a solid line
						int divider = brushWidth / 4;
						int steps = d / (divider);// how many dots has to be
													// drawn
						for (int i = 0; i < steps; i++) {
							int x = (int) ((line.startX + ((divider) * (i))
									* n_x));
							int y = (int) ((line.startY + ((divider) * (i))
									* n_y));
							if (x != 0 && y != 0) {
								g.fillArc(x, y, brushWidth, brushWidth, 0, 360);
								img_g.fillArc(x, y - ToolBarView.HEIGHT,
										brushWidth, brushWidth, 0, 360);
							}
						}
					}
				}
				g.fillArc((int) line.endX, (int) line.endY, brushWidth,
						brushWidth, 0, 360);
				img_g.fillArc((int) line.endX,
						(int) line.endY - ToolBarView.HEIGHT, brushWidth,
						brushWidth, 0, 360);
			}
		}

	}

	private int calcDistance() {
		double x = (brush_x > previous_x) ? brush_x - previous_x : previous_x
				- brush_x;
		double y = (brush_y > previous_y) ? brush_y - previous_y : previous_y
				- brush_y;
		if (x < 0) {
			x = x * (-1);
		}
		if (y < 0) {
			y = y * (-1);
		}
		int dist = (int) Math.sqrt(x * x + y * y);
		return dist;
	}

	protected void pointerDragged(int aX, int aY) {
		if (drawingAllowed) {
//			if (aY > ToolBarView.HEIGHT) {
			if (drawArea.isPointInside(aX, aY)) {
				previous_x = brush_x;
				previous_y = brush_y;
				brush_x = aX;
				brush_y = aY;
				buffer.addElement(new DrawableLine(previous_x, previous_y,
						brush_x, brush_y, brushColor));
			}
		}
	}

	protected void pointerPressed(int aX, int aY) {
		if (drawingAllowed) {
			if (drawArea.isPointInside(aX, aY)) {
				brush_x = aX;
				brush_y = aY;
				buffer.addElement(new DrawableLine(brush_x, brush_y, brush_x,
						brush_y, brushColor));
			} else {
				toolbar.pointerPressed(aX, aY);
			}

		} else {
//			if (savedialog.isVisible()) {
//				savedialog.pointerPressed(aX, aY);
//			}
		}
	}

	protected void pointerReleased(int aX, int aY) {
		if (!drawingAllowed) {
//			if (colorpicker.isVisible()) {
//				colorpicker.pressed(aX, aY);
//			} else if (savedialog.isVisible()) {
//				savedialog.pointerUnpressed(aX, aY);
//			}
		} else {
			previous_x = -1;
			previous_y = -1;
			brush_x = -1;
			brush_y = -1;
			toolbar.pointerUnpressed(aX, aY);
		}
	}

	public Image getDrawing() {
		return drawing;
	}

	public void setBrush(final int brushsize) {
		if(brushsize < SMALL_BRUSH || brushsize > XL_BRUSH)
			return;
		brushWidth = brushsize;
	}

	public void colorChanged(int newRGBColor) {
		brushColor = newRGBColor;
	}

	public void openImage(Image image) {
		//TODO:
	}
	
	/**
	 * Clear graphic object of gr parameter
	 * @param gr
	 */
	private void clearGraphic(Graphics gr) {
		int oldcolor = gr.getColor();
		gr.setColor(0xffffff);
		gr.fillRect(0, 0, gr.getClipWidth(), gr.getClipHeight());
		gr.setColor(oldcolor);
	}

	/**
	 * Clear drawing area
	 */
	public void clearDrawing() {
		int oldcolor = g.getColor();
		img_g.setColor(0xffffff);
		g.setColor(0xffffff);
		img_g.fillRect(0, 0, drawing.getWidth(), drawing.getHeight());
		g.fillRect(0, ToolBarView.HEIGHT, drawing.getWidth(), drawing.getHeight());
		img_g.setColor(oldcolor);
		g.setColor(oldcolor);
	}

	public void allowDrawing(boolean value) {
		if (value) {
			renderDrawing = true;
		}
		drawingAllowed = value;
	}

}